import { AppError, notFound } from "@autoscholar/core"; import { artifacts } from "@autoscholar/db"; import { and, desc, eq } from "drizzle-orm"; import { handler } from "@/lib/server/api"; import { db, storage } from "@/lib/server/db"; import { requireAdmin } from "@/lib/server/session"; export const runtime = "nodejs"; /** Private artifact download for admins (latest version unless ?version=n). */ export const GET = handler(async (req, { params }) => { await requireAdmin(req); const { id, path } = (await params) as { id: string; path: string[] }; const rel = path.map(decodeURIComponent).join("/"); if (rel.includes("..")) throw new AppError("invalid", "bad path", 400); const url = new URL(req.url); const version = url.searchParams.get("version"); const conds = [eq(artifacts.runId, id), eq(artifacts.path, rel)]; if (version) conds.push(eq(artifacts.version, Number(version))); const [row] = await db() .select() .from(artifacts) .where(and(...conds)) .orderBy(desc(artifacts.version)) .limit(1); if (!row) throw notFound("artifact"); const buf = await storage().get(row.storageKey); const inline = /^(application\/pdf|image\/|text\/)/.test(row.contentType) && url.searchParams.get("download") !== "1"; return new Response(new Uint8Array(buf), { headers: { "content-type": row.contentType, "content-length": String(buf.length), "content-disposition": `${inline ? "inline" : "attachment"}; filename="${rel.split("/").pop()}"`, "x-artifact-sha256": row.sha256, "cache-control": "private, no-store", "content-security-policy": "sandbox", }, }); });